package cn.imu.config;

import cn.imu.entity.StatisticsEntity;
import cn.imu.entity.User;
import cn.imu.service.StatisticsService;
import cn.imu.service.UserService;
import cn.imu.utils.DateUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;

import java.sql.Timestamp;
import java.util.concurrent.TimeUnit;

/**
 * @author 杨鑫
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private StatisticsService statisticsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    User user;
    //用户登录失败次数计数  redisKey 前缀
    private String SHIRO_LOGIN_COUNT_FAIL = "shiro_login_count_fail_";

    //用户登录成功次数计数  redisKey 前缀
    private String SHIRO_LOGIN_COUNT_SUCCESS = "shiro_login_count_success_";
    //用户登录是否被锁定  redisKey 前缀
    private String SHIRO_IS_LOCK = "shiro_is_lock_";
    //int  count=0;
    //HttpSession session;



    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=》授权doGetAuthorizationInfo");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        authorizationInfo.addStringPermission("user:add");
        //拿到当前登录的这个对象
        Subject subject = SecurityUtils.getSubject();
        //拿到user对象
        User currentUser = (User)subject.getPrincipal();
        //设置当前用户的权限
        authorizationInfo.addStringPermission(currentUser.getPerms());
        return authorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=》认证doGetAuthenticationInfo");
        //拿到用户名密码令牌
        UsernamePasswordToken userToken=(UsernamePasswordToken)  authenticationToken;
        String userName=userToken.getUsername();
        String userPassword=new String(userToken.getPassword());
        System.out.println("userName:"+userName);
        System.out.println("userPassword:"+userPassword);

        //连接真实数据库
         user = userService.queryUserByName(userToken.getUsername());
       //登录成功后，在session中放值，便于判断
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginUser",user);

        //访问一次，计数一次
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        //count++;
        //每次增加1
        /*
        9、increment(K key, double delta)
        以增量的方式将double值存储在变量中。
       double stringValueDouble=redisTemplate.opsForValue().increment("doubleKey",5);
         */


        if(user==null){
            //opsForValue.increment(SHIRO_LOGIN_COUNT_FAIL+userName,1);
            throw new UnknownAccountException("账号不存在！");

        }else if(!user.getPwd().equals(userPassword)){
            System.out.println("登录失败，redis中失败的计数+1");
            opsForValue.increment(SHIRO_LOGIN_COUNT_FAIL+userName,1);
            throw new IncorrectCredentialsException("密码不正确！");
        }else if(!user.getName().equals(userName)){
            //opsForValue.increment(SHIRO_LOGIN_COUNT_FAIL+userName,1);
            throw new UnknownAccountException("用户名错误");
        }
        else{
            System.out.println("登录成功，redis中成功的计数+1");
            opsForValue.increment(SHIRO_LOGIN_COUNT_SUCCESS+userName,1);
        }

        StatisticsFromRedis();
        //密码认证，shiro做,加密了,MD5,MD5加盐
        //将user返回，用于授权
        SimpleAuthenticationInfo simpleAuthenticationInfo =
                new SimpleAuthenticationInfo(user.getName(), user.getPwd(),getName());


        return simpleAuthenticationInfo;

    }



    //封装，执行每天凌晨2点统计用户登录的次数
    //cron = "0 0 2 * * ?" ->每天凌晨2点
    //0 0/1 * * * ? 从0分钟开始，每分钟执行一次
    @Scheduled(cron = "0 0/1 * * * ?")
    public void StatisticsFromRedis(){
       String  userName=user.getName();
       System.out.println(userName);
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        //缓存中用户登录失败的次数
        int FailCount=Integer.parseInt(opsForValue.get(SHIRO_LOGIN_COUNT_FAIL+userName));
        //缓存中用户登录成功的次数
        int SuccessCount=Integer.parseInt(opsForValue.get(SHIRO_LOGIN_COUNT_SUCCESS+userName));
        // opsForValue.set(SHIRO_LOGIN_COUNT+userName,String.valueOf(count));
        //System.out.println("aaaaaa");
        // System.out.println(FailCount);
        System.out.println(userName+": 账户登录失败的次数是： "+FailCount);
        System.out.println(userName+": 账户登录成功的次数是： "+SuccessCount);
  /*      //实现登录失败5次锁定
        if(FailCount>=5){
            opsForValue.set(SHIRO_IS_LOCK+userName, "LOCK");  //锁住这个账号，值是LOCK。
            //expire  变量存活期限，设置过期时间为1分钟
            stringRedisTemplate.expire(SHIRO_IS_LOCK+userName, 1, TimeUnit.MINUTES);

        }
        //如果这个账号登陆异常，则在登陆页面提醒
        if(FailCount>=5){
            //读出redis中的值放到shrio的session中，判断其是否大于0
            session.setAttribute("count",FailCount);
            if("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK+userName))){

                //count=0;
                //清空登录计数
                opsForValue.set(SHIRO_LOGIN_COUNT_FAIL+userName, "0");
                //清空锁
                opsForValue.set(SHIRO_IS_LOCK+userName, "");
                //计数大于5次，设置用户被锁定一分钟
                throw new LockedAccountException("由于输入错误次数大于5次，帐号1分钟内已经禁止登录！");
            }
        }*/
        //全部登录次数
        //int login_count=FailCount+SuccessCount;

        //获得当前系统时间
        Timestamp loginTime = DateUtils.nowDateTime();
        StatisticsEntity statisticsEntity = new StatisticsEntity();
        statisticsEntity.setUserName(userName);
        statisticsEntity.setFailCount(FailCount);
        statisticsEntity.setSuccessCount(SuccessCount);
        statisticsEntity.setLoginCount(FailCount,SuccessCount);
        statisticsEntity.setStatisticsDate(loginTime);
        int result=statisticsService.insertStatistics(statisticsEntity);
        //session.setAttribute("result",result);
        if(result>0){
            System.out.println("统计成功");
        }else {
            System.out.println("统计失败");
        }
    }

}
